import logging

import pandas as pd

logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s | %(filename)s - {%(lineno)d} - [%(levelname)s] - %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S', encoding='utf-8')


class StockCalculate:

    def __init__(self, dataFrame):
        if not dataFrame.empty:
            self.pd = pd.DataFrame()
            self.pd["code"] = dataFrame[0]
            self.pd["date"] = dataFrame[1]
            self.pd["open"] = dataFrame[2]
            self.pd["close"] = dataFrame[3]
            self.pd["high"] = dataFrame[4]
            self.pd["low"] = dataFrame[5]
            self.pd["vol"] = dataFrame[6]
            self.pd["vol_amount"] = dataFrame[7]
            self.pd["change"] = dataFrame[8]
            self.pd["increment"] = dataFrame[9]

            self.pd["zz"] = (self.pd["open"] + self.pd["low"] + self.pd["high"]) / 3
            self.pd["zl1"] = self.pd["zz"].ewm(span=8, adjust=True).mean().round(2)
            self.pd["zl2"] = self.pd["zz"].ewm(span=55, adjust=True).mean().round(2)
            self.pd = self.pd.drop('zz', axis=1)
            self.pd['dif'] = self.pd["close"].ewm(span=12, adjust=False).mean() - self.pd["close"].ewm(span=26,adjust=False).mean()
            self.pd['dea'] = self.pd["dif"].ewm(span=9, adjust=False).mean()
            self.pd['macd'] = 2 * (self.pd["dif"] - self.pd["dea"])

        else:
            self.pd = pd.DataFrame()

    def calculate(self):
        if not self.pd.empty:
            for index in range(0, len(self.pd)):
                try:
                    self.pd.loc[index, "date"] = self.pd.loc[index, "date"].strftime("%Y-%m-%d")
                    ## c1 condition (zl1 > zl2)
                    if self.pd.loc[index, "zl1"] > self.pd.loc[index, "zl2"]:
                        self.pd.loc[index, "c1"] = 1
                    else:
                        self.pd.loc[index, "c1"] = 0

                    ## c2 condition (c < zl2)
                    if self.pd.loc[index, "close"] <= self.pd.loc[index, "zl1"]:
                        self.pd.loc[index, "c2_1"] = 1
                    else:
                        self.pd.loc[index, "c2_1"] = 0

                    if index >= self.n - 1:
                        ## [0:2]
                        pd2 = self.pd.loc[index - self.n + 1:index - self.n + self.p + 1]
                        if pd2.loc[pd2["c2_1"] == 1].shape[0] == self.p:
                            self.pd.loc[index, "c2"] = 1
                        else:
                            self.pd.loc[index, "c2"] = 0
                    else:
                        self.pd.loc[index, "c2"] = 0

                    ## c3 condition (c > zl1)
                    if self.pd.loc[index, "close"] >= self.pd.loc[index, "zl1"]:
                        self.pd.loc[index, "c3_2"] = 1
                    else:
                        self.pd.loc[index, "c3_2"] = 0

                    if index >= self.p + 2:
                        pd3 = self.pd.loc[index - self.p + 1:index]
                        pd4 = self.pd.loc[index - self.p]
                        pd5 = self.pd.loc[index - self.p - 1]
                        pd6 = self.pd.loc[index - self.p - 2]
                        if pd3.loc[pd3["c3_2"] == 1].shape[0] >= self.p and (
                                pd4["open"] <= pd4["zl1"] <= pd4["close"] or pd5["open"] <= pd5["zl1"] <= pd5[
                            "close"] or
                                pd6["open"] <= pd6["zl1"] <= pd6["close"]):
                            self.pd.loc[index, "c3"] = 1
                        else:
                            self.pd.loc[index, "c3"] = 0
                    else:
                        self.pd.loc[index, "c3"] = 0

                    ## c4 condition abs(v/ref(v,1)) <=0.15
                    if index >= 1 and self.pd.loc[index - 1, "close"] is not None:
                        if abs(self.pd.loc[index, "vol"] - self.pd.loc[index - 1, "vol"]) / self.pd.loc[
                            index - 1, "vol"] <= self.p1:
                            self.pd.loc[index, "c4"] = 1
                        else:
                            self.pd.loc[index, "c4"] = 0
                    else:
                        self.pd.loc[index, "c4"] = 0

                    ## c5 ma_cd.dif upload
                    if index >= 1 and self.pd.loc[index - 1, "dif"] is not None:
                        if self.pd.loc[index, "dif"] >= self.pd.loc[index - 1, "dif"]:
                            self.pd.loc[index, "c5"] = 1
                        else:
                            self.pd.loc[index, "c5"] = 0
                    else:
                        self.pd.loc[index, "c5"] = 0

                    ## c6 close > open and close > zl1
                    if self.pd.loc[index, "close"] > self.pd.loc[index, "zl1"] and self.pd.loc[index, "close"] > \
                            self.pd.loc[
                                index, "open"]:
                        self.pd.loc[index, "c6"] = 1
                    else:
                        self.pd.loc[index, "c6"] = 0

                    # c7 high - close / last(close) < p2(0.03)
                    if index >= 1 and (self.pd.loc[index, "high"] - self.pd.loc[index, "close"]) / self.pd.loc[
                        index - 1, "close"] <= self.p2:
                        self.pd.loc[index, "c7"] = 1
                    else:
                        self.pd.loc[index, "c7"] = 0

                    # c8
                    if index >= 2 and self.pd.loc[index, "close"] > self.pd.loc[index - 1, "close"] and \
                            self.pd.loc[
                                index, "close"] > self.pd.loc[index - 2, "close"]:
                        self.pd.loc[index, "c8_1"] = 1
                    else:
                        self.pd.loc[index, "c8_1"] = 0

                    if index >= 2 and self.pd.loc[index - 1, "c8_1"] == 1 and self.pd.loc[
                        index - 1, "close"] >= self.pd.loc[index, "close"] >= self.pd.loc[index - 2, "close"]:
                        self.pd.loc[index, "c8_2"] = 1
                    else:
                        self.pd.loc[index, "c8_2"] = 0

                    if index >= 2 and self.pd.loc[index - 1, "c8_2"] == 1 and self.pd.loc[
                        index - 2, "close"] >= self.pd.loc[index, "close"] >= self.pd.loc[index - 1, "close"]:
                        self.pd.loc[index, "c8_3"] = 1
                    else:
                        self.pd.loc[index, "c8_3"] = 0

                    if index >= 2 and self.pd.loc[index - 1, "c8_3"] == 1 and self.pd.loc[
                        index - 1, "close"] >= self.pd.loc[index, "close"] >= self.pd.loc[index - 2, "close"]:
                        self.pd.loc[index, "c8_4"] = 1
                    else:
                        self.pd.loc[index, "c8_4"] = 0

                    if index >= 2 and self.pd.loc[index - 1, "c8_4"] == 1 and self.pd.loc[
                        index - 2, "close"] >= self.pd.loc[index, "close"] >= self.pd.loc[index - 1, "close"]:
                        self.pd.loc[index, "c8_5"] = 1
                    else:
                        self.pd.loc[index, "c8_5"] = 0

                    if index >= 2 and self.pd.loc[index - 1, "c8_5"] == 1 and self.pd.loc[
                        index - 1, "close"] >= self.pd.loc[index, "close"] >= self.pd.loc[index - 2, "close"]:
                        self.pd.loc[index, "c8_6"] = 1
                    else:
                        self.pd.loc[index, "c8_6"] = 0

                    if index >= 2 and self.pd.loc[index - 1, "c8_6"] == 1 and self.pd.loc[
                        index - 2, "close"] >= self.pd.loc[index, "close"] >= self.pd.loc[index - 1, "close"]:
                        self.pd.loc[index, "c8_7"] = 1
                    else:
                        self.pd.loc[index, "c8_7"] = 0

                    if index >= 2 and self.pd.loc[index - 1, "c8_7"] == 1 and self.pd.loc[
                        index - 1, "close"] >= self.pd.loc[index, "close"] >= self.pd.loc[index - 2, "close"]:
                        self.pd.loc[index, "c8_8"] = 1
                    else:
                        self.pd.loc[index, "c8_8"] = 0

                    if index >= 2 and self.pd.loc[index - 1, "c8_8"] == 1 and self.pd.loc[
                        index - 2, "close"] >= self.pd.loc[index, "close"] >= self.pd.loc[index - 1, "close"]:
                        self.pd.loc[index, "c8_9"] = 1
                    else:
                        self.pd.loc[index, "c8_9"] = 0

                    if index >= 2 and self.pd.loc[index - 1, "c8_9"] == 1 and self.pd.loc[
                        index - 1, "close"] >= self.pd.loc[index, "close"] >= self.pd.loc[index - 2, "close"]:
                        self.pd.loc[index, "c8_10"] = 1
                    else:
                        self.pd.loc[index, "c8_10"] = 0

                    if index >= 2 and self.pd.loc[index - 1, "c8_10"] == 1 and self.pd.loc[
                        index - 2, "close"] >= self.pd.loc[index, "close"] >= self.pd.loc[index - 1, "close"]:
                        self.pd.loc[index, "c8_11"] = 1
                    else:
                        self.pd.loc[index, "c8_11"] = 0

                    if index >= 2 and self.pd.loc[index - 1, "c8_11"] == 1 and self.pd.loc[
                        index - 1, "close"] >= self.pd.loc[index, "close"] >= self.pd.loc[index - 2, "close"]:
                        self.pd.loc[index, "c8_12"] = 1
                    else:
                        self.pd.loc[index, "c8_12"] = 0

                    # c9
                    if index >= 2 and self.pd.loc[index, "close"] < self.pd.loc[index - 1, "close"] and \
                            self.pd.loc[
                                index, "close"] < self.pd.loc[index - 2, "close"]:
                        self.pd.loc[index, "c9_1"] = 1
                    else:
                        self.pd.loc[index, "c9_1"] = 0

                    if index >= 2 and self.pd.loc[index - 1, "c9_1"] == 1 and self.pd.loc[index - 1, "close"] <= \
                            self.pd.loc[
                                index, "close"] <= self.pd.loc[index - 2, "close"]:
                        self.pd.loc[index, "c9_2"] = 1
                    else:
                        self.pd.loc[index, "c9_2"] = 0

                    if index >= 2 and self.pd.loc[index - 1, "c9_2"] == 1 and self.pd.loc[index - 2, "close"] <= \
                            self.pd.loc[
                                index, "close"] <= self.pd.loc[index - 1, "close"]:
                        self.pd.loc[index, "c9_3"] = 1
                    else:
                        self.pd.loc[index, "c9_3"] = 0

                    if index >= 2 and self.pd.loc[index - 1, "c9_3"] == 1 and self.pd.loc[index - 1, "close"] <= \
                            self.pd.loc[
                                index, "close"] <= self.pd.loc[index - 2, "close"]:
                        self.pd.loc[index, "c9_4"] = 1
                    else:
                        self.pd.loc[index, "c9_4"] = 0

                    if index >= 2 and self.pd.loc[index - 1, "c9_4"] == 1 and self.pd.loc[index - 2, "close"] <= \
                            self.pd.loc[
                                index, "close"] <= self.pd.loc[index - 1, "close"]:
                        self.pd.loc[index, "c9_5"] = 1
                    else:
                        self.pd.loc[index, "c9_5"] = 0

                    if index >= 2 and self.pd.loc[index - 1, "c9_5"] == 1 and self.pd.loc[index - 1, "close"] <= \
                            self.pd.loc[
                                index, "close"] <= self.pd.loc[index - 2, "close"]:
                        self.pd.loc[index, "c9_6"] = 1
                    else:
                        self.pd.loc[index, "c9_6"] = 0

                    if index >= 2 and self.pd.loc[index - 1, "c9_6"] == 1 and self.pd.loc[index - 2, "close"] <= \
                            self.pd.loc[
                                index, "close"] <= self.pd.loc[index - 1, "close"]:
                        self.pd.loc[index, "c9_7"] = 1
                    else:
                        self.pd.loc[index, "c9_7"] = 0

                    if index >= 2 and self.pd.loc[index - 1, "c9_7"] == 1 and self.pd.loc[index - 1, "close"] <= \
                            self.pd.loc[
                                index, "close"] <= self.pd.loc[index - 2, "close"]:
                        self.pd.loc[index, "c9_8"] = 1
                    else:
                        self.pd.loc[index, "c9_8"] = 0

                    if index >= 2 and self.pd.loc[index - 1, "c9_8"] == 1 and self.pd.loc[index - 2, "close"] <= \
                            self.pd.loc[
                                index, "close"] <= self.pd.loc[index - 1, "close"]:
                        self.pd.loc[index, "c9_9"] = 1
                    else:
                        self.pd.loc[index, "c9_9"] = 0

                    if index >= 2 and self.pd.loc[index - 1, "c9_9"] == 1 and self.pd.loc[index - 1, "close"] <= \
                            self.pd.loc[
                                index, "close"] <= self.pd.loc[index - 2, "close"]:
                        self.pd.loc[index, "c9_10"] = 1
                    else:
                        self.pd.loc[index, "c9_10"] = 0

                    if index >= 2 and self.pd.loc[index - 1, "c9_10"] == 1 and self.pd.loc[index - 2, "close"] <= \
                            self.pd.loc[
                                index, "close"] <= self.pd.loc[index - 1, "close"]:
                        self.pd.loc[index, "c9_11"] = 1
                    else:
                        self.pd.loc[index, "c9_11"] = 0

                    if index >= 2 and self.pd.loc[index - 1, "c9_11"] == 1 and self.pd.loc[index - 1, "close"] <= \
                            self.pd.loc[
                                index, "close"] <= self.pd.loc[index - 2, "close"]:
                        self.pd.loc[index, "c9_12"] = 1
                    else:
                        self.pd.loc[index, "c9_12"] = 0

                    # c8 buy
                    if index >= 1 and (self.pd.loc[index - 1, "c9_1"] == 1 or
                                       self.pd.loc[index - 1, "c9_2"] == 1 or
                                       self.pd.loc[index - 1, "c9_3"] == 1 or
                                       self.pd.loc[index - 1, "c9_4"] == 1 or
                                       self.pd.loc[index - 1, "c9_5"] == 1 or
                                       self.pd.loc[index - 1, "c9_6"] == 1 or
                                       self.pd.loc[index - 1, "c9_7"] == 1 or
                                       self.pd.loc[index - 1, "c9_8"] == 1 or
                                       self.pd.loc[index - 1, "c9_9"] == 1 or
                                       self.pd.loc[index - 1, "c9_10"] == 1 or
                                       self.pd.loc[index - 1, "c9_11"] == 1 or
                                       self.pd.loc[index - 1, "c9_12"] == 1) and self.pd.loc[index, "c8_1"] == 1:
                        self.pd.loc[index, "c8"] = 1
                    else:
                        self.pd.loc[index, "c8"] = 0

                    # c9 sell
                    if index >= 1 and (self.pd.loc[index - 1, "c8_1"] == 1 or
                                       self.pd.loc[index - 1, "c8_2"] == 1 or
                                       self.pd.loc[index - 1, "c8_3"] == 1 or
                                       self.pd.loc[index - 1, "c8_4"] == 1 or
                                       self.pd.loc[index - 1, "c8_5"] == 1 or
                                       self.pd.loc[index - 1, "c8_6"] == 1 or
                                       self.pd.loc[index - 1, "c8_7"] == 1 or
                                       self.pd.loc[index - 1, "c8_8"] == 1 or
                                       self.pd.loc[index - 1, "c8_9"] == 1 or
                                       self.pd.loc[index - 1, "c8_10"] == 1 or
                                       self.pd.loc[index - 1, "c8_11"] == 1 or
                                       self.pd.loc[index - 1, "c8_12"] == 1) and self.pd.loc[index, "c9_1"] == 1:
                        self.pd.loc[index, "c9"] = 1
                    else:
                        self.pd.loc[index, "c9"] = 0

                    # c10(红箭头)
                    if index >= 2 and self.pd.loc[index, "close"] > self.pd.loc[index, "zl1"] and self.pd.loc[
                        index, "c8"] > 0:
                        self.pd.loc[index, "c10"] = 1
                    else:
                        self.pd.loc[index, "c10"] = 0

                    if index > self.n and \
                            (self.pd.loc[index - self.n + 1:index][
                                self.pd.loc[index - self.n + 1:index]["c10"] > 0]).shape[
                                0] >= 1:
                        self.pd.loc[index, "c11"] = 1
                    else:
                        self.pd.loc[index, "c11"] = 0

                    if self.pd.loc[index, "macd"] >= 0:
                        self.pd.loc[index, "c12"] = 1
                    else:
                        self.pd.loc[index, "c12"] = 0

                    # condition constructor
                    if (self.pd.loc[index, "c1"] > 0 and self.pd.loc[index, "c2"] > 0
                            and self.pd.loc[index, "c3"] > 0 and self.pd.loc[index, "c4"] > 0
                            and self.pd.loc[index, "c5"] > 0 and self.pd.loc[index, "c6"] > 0
                            and self.pd.loc[index, "c7"] > 0 and self.pd.loc[index, "c11"] > 0
                            and self.pd.loc[index, "c12"] > 0):
                        self.pd.loc[index, "flag"] = 1
                    else:
                        self.pd.loc[index, "flag"] = 0
                except Exception as e:
                    print('error', e)

    def output(self):
        if not self.pd.empty:
            output_value_list = []
            output_pd = self.pd.loc[self.pd["flag"] > 0]
            if output_pd.shape[0] > 0:
                for idx in output_pd.index:
                    stock_code = self.pd.loc[idx, "code"]
                    stock_date = output_pd.loc[idx, "date"]
                    stock_close = output_pd.loc[idx, "close"].item()
                    start_index = idx - 4
                    end_index = idx + 5

                    ## before params value
                    f_value_list = []
                    f_idx = 1
                    for f_index in range(start_index, idx + 1):
                        f_value_list.append({
                            "idx": f_idx,
                            "open": self.pd.loc[f_index, "open"].item(),
                            "close": self.pd.loc[f_index, "close"].item(),
                            "high": self.pd.loc[f_index, "high"].item(),
                            "low": self.pd.loc[f_index, "low"].item(),
                            "vol": self.pd.loc[f_index, "vol"].item(),
                            "change": self.pd.loc[f_index, "change"].item(),
                            "vol_amount": self.pd.loc[f_index, "vol_amount"].item(),
                            "increment": self.pd.loc[f_index, "increment"].item(),
                            "zl1": self.pd.loc[f_index, "zl1"].item(),
                            "zl2": self.pd.loc[f_index, "zl2"].item(),
                        })
                        f_idx += 1

                    ## later result value
                    max_high = min_low = max_close = None
                    if end_index < self.pd.shape[0]:
                        new_pd = self.pd.loc[idx + 1:end_index]
                        max_high = new_pd["high"].max()
                        max_close = new_pd["close"].max()
                        min_low = new_pd["low"].min()

                    ## data into output_value_list
                    output_value_list.append({
                        "stock_code": stock_code,
                        "stock_date": stock_date,
                        "close": stock_close,
                        "high": max_high,
                        "low": min_low,
                        "max_close": max_close,
                        "params": f_value_list
                    })

            return output_value_list
        else:
            return None
